FFMPEG通过管道将图片推送流媒体

您所在的位置:网站首页 ffmpeg 发送数据 FFMPEG通过管道将图片推送流媒体

FFMPEG通过管道将图片推送流媒体

#FFMPEG通过管道将图片推送流媒体| 来源: 网络整理| 查看: 265

         最近遇到个需求,将私有协议的码流,就是比较老的视频设备啦,新设备都支持标准H264,H265了,或者私有平台协议的视频,将这些私有协议视频通过转码推送到标准的流媒体服务器,然后通过网页不使用插件进行。目前无插件播放的播放器很多比如video.js啦,一般只支持H264的flv格式,HLS等,当然也有支持H265的,不过这些都不是重点,今天的重点是怎么通过FFMPEG将私有协议的码流转化为标准的H264然后通过FFMPEG推送到流媒体服务器,从而通过网页直接播放。

        这个需求嘛,做的方式也很多,比如先对接私有SDK,然后通过私有解码库解码为YVU然后在编码转发,这是一个比较普遍的做法,也很常规。不过其实比较麻烦, 需要对编解码有一定基础。下面我介绍的方法较为简单,也很通用,只需要私有SDK支持抓图功能即可,一般私有SDK抓图的接口基本都有。

      主要思路就是使用私有SDK的抓图接口,不停的抓图,然后将图片数据输送到FFMPEG的管道,这样就可以源源不断的推送了。

     首先是FFMPEG的管道命令使用方法 

      ffmpeg.exe -f image2pipe -i \\.\\pipe\MyPipe -pix_fmt yuv420p -vcodec libx264 -f rtsp -rtsp_transport tcp "rtsp://127.0.0.1:8554/1234/1"

     调用这个命令后,FFMPEG就会连接\\.\\pipe\MyPipe的命名管道,如果没有打开命名管道,FFMPEG会退出,如果有,则会等待管道数据,我们就是利用此功能进行推送

     好了,废话不多说,上干货,也就是代码,这里以windows为例,linux大同小异就是管道的使用方法不同而已,大家学会举一反三

 

long StartProgress()//调用FFMPEG命令推流 {     char sProcessID[32] = {0};     sprintf_s(sProcessID,sizeof(sProcessID),"%d",GetCurrentProcessId());

    char sparam[1024];     //调用FFMPEG命令通过管道数据推流,这里想推什么流改后面的推流地址即可,FFMPEG很强大的     sprintf(sparam,"ffmpeg.exe -f image2pipe -i \\\\.\\pipe\\MyPipe -pix_fmt yuv420p -vcodec libx264 -f rtsp -rtsp_transport tcp \"rtsp://127.0.0.1:8554/1234/1\"");

    PROCESS_INFORMATION pi;     STARTUPINFO    si;     memset(&si, 0, sizeof(si));     si.cb = sizeof(STARTUPINFO);     si.dwFlags = STARTF_USESHOWWINDOW;     si.lpTitle = "";     si.wShowWindow = SW_SHOWNORMAL;

    DWORD dwExitCode =0;     BOOL ret = ::CreateProcess(NULL,(char*)sparam, NULL, NULL, FALSE,CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);     if (ret)     {                  //m_lpid = pi.dwProcessId;

        //GF_AddProcessToJobObject(pi.hProcess);         //关闭子进程的主线程句柄                  //等待子进程的退出         //WaitForSingleObject(pi.hProcess,INFINITE);         //获取子进程的退出码         //GetExitCodeProcess(pi.hProcess, &dwExitCode);

        //::CloseHandle((HANDLE)pi.dwProcessId);          ::CloseHandle((HANDLE)pi.hThread);         //关闭子进程句柄         //CloseHandle(pi.hProcess);     }else     {         //LOGE         // add a NULL disc. ACL to the security descriptor.         if (SetSecurityDescriptorDacl(&sd, TRUE, (PACL) NULL, FALSE))         {             sa.nLength = sizeof(sa);             sa.lpSecurityDescriptor =&sd;             sa.bInheritHandle = TRUE;             //创建一个命名管道,在windows中\代表zhuan'yi两个\\代表一个\              HANDLE hNamedPipe = CreateNamedPipeA("\\\\.\\pipe\\MyPipe",                  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,                  PIPE_TYPE_BYTE, 1, 1024, 1024,0 , &sa);              //检查是否创建成功              if (hNamedPipe == INVALID_HANDLE_VALUE)              {                  printf("create named pipe failed!\n");              }              else              {                  printf("create named pipe success!\n");              } 

            //异步IO结构              OVERLAPPED op;              ZeroMemory(&op, sizeof(OVERLAPPED));              //创建一个事件内核对象              op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);              //等待一个客户端进行连接              BOOL b = ConnectNamedPipe(hNamedPipe, &op);              //开启FFMPEG,并调用命令             StartProgress();             //当有客户端进行连接时,事件变成有信号的状态              if (WaitForSingleObject(op.hEvent, INFINITE) == 0)              {                  printf("client connect success!\n");              }              else              {                  printf("client connect failed!\n");              } 

            unsigned char*  buff = new unsigned char[1024*1024*100];              memset(buff,0,1024*1024*100);             CFile file;                          while(TRUE)             {                 if(m_lPlayBackHandle == -1)                     return -1;

                //下面的函数就是私有SDK抓图函数,自己改为自己的抓图接口即可

                str.Format("G:\\test\\conver\\bin\\1234\\1.bmp",num);                 GF_CreateDir(str);                 int nRes = EX_NET_CapturePicture(0,m_lPlayBackHandle,(char*)(LPCTSTR)str);

                //--------抓图接口抓图完成后,读取图像数据,通过管道输入到FFMPEG                 if(file.Open(str,CFile::modeReadWrite))                 {                         memset(buff,0,1024*1024*100);                     int nLen = file.Read(buff,1024*1024*100);                     DWORD cbWrite;                      WriteFile(hNamedPipe, buff, nLen, &cbWrite, NULL);                      file.Close();                 }                 Sleep(10);             }         }     }     return 0xFFFF; }

 

效果图上个

说明推流成功啦

VLC播放效果

CPU占用略高,FFMPEG转码占用CPU本身比较高

我I5的CPU大概解码15%,编码15%左右

此文仅用来抛砖引玉,给出个思路,具体应用到项目中,还需很多工作



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3